﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using ENGINE;
using Models;
using System.Threading;

namespace Graphics
{
    public partial class Form1 : Form
    {
        MorphingModel[] SceneModels = new MorphingModel[6];
        Texture[] SceneTextures = new Texture[6];
        bool PaintScene = true;
        double SceneAngle1 = 0;
        double SceneAngle2 = 0;
        bool SceneScannerOpen = false;
        bool ScenePrinterOpen = true;
        bool ScenePrintStarted = false;
        double OpenSpeed1 = 0.004;
        double OpenSpeed2 = 0.001;
        static Int16 LengthSegments = 10;
        double[] Points = new double[LengthSegments * 6];//Эти массивы - лист бумаги.
        double[] TexCoords = new double[LengthSegments * 4];
        int[] Faces_TexFaces = new int[LengthSegments * 6];
        int[] color ={ 255, 255, 255 };
        double LengthT = 40;
        double ParamT = 0;
        double SpeedT = 0.005;

        
        Buffers current;
        MorphingModel Model;
        Texture tex;
        Int32 LastTickCount;
        Int32 LastFixedFPS;
        Int32 FPS;
        double RotateAngleY = 0;
        double RotateAngleX = 0;
        double LightAngle = 0;
        double RotateSpeed = Math.PI / 5000;
        double Scale = 1;
        Color ModelColor = Color.Yellow;
        Color ClearColor = Color.Green;
        bool RotateLight = false;
        bool RotateXModel = false;
        bool RotateYModel = false;
        bool OnlyFaceNormals = true;
        Texture MainTexture;

        public void GetYZ(double t, out double y, out double z, out double Copyy, out double Copyz)
        {
            if (t <= 35) { z = t - 35; y = 0.25; }
            else if (t < 50){ z = 7 - Math.Abs(t - 43.061); y = -1- (t - 43.061) / 7; }
            else if (t < 76.123) { z = 50 - t; y = -2; }
            else { z = 76.123 - t - 25; y = -2 + 0.17 * (t - 76.123); }
            Copyy = y; Copyz = z;
        }
        public void LoadScene()
        {
            current.EnableDoubleNormals = true;
            SceneModels[0] = new MorphingModel("Models\\Printer_Main.mx1", false, true);
            SceneModels[1] = new MorphingModel("Models\\Printer_Inside.mx1", false, true);
            SceneModels[2] = new MorphingModel("Models\\Printer_LeftRight.mx1", false,true);
            SceneModels[3] = new MorphingModel("Models\\Printer_Buttons.mx1", false, true);
            SceneModels[4] = new MorphingModel("Models\\Printer_Scanner.mx1", false,true);
            SceneModels[5] = new MorphingModel("Models\\Printer_Door.mx1", false, true);
            for (byte i=0;i!=6;i++)
                SceneTextures[i]=new Texture("Textures\\"+((Byte)(i+1)).ToString()+".JPG");
            for (Int16 i = 0; i != LengthSegments - 2; i++)
            {
                Faces_TexFaces[i * 6] = i;
                Faces_TexFaces[i * 6 + 1] = i + 1;
                Faces_TexFaces[i * 6 + 2] = LengthSegments + i + 1;
                Faces_TexFaces[i * 6 + 3] = LengthSegments + i + 1;
                Faces_TexFaces[i * 6 + 4] = LengthSegments + i;
                Faces_TexFaces[i * 6 + 5] = i;
            }
            for (Int16 i = 0; i != LengthSegments; i++)
                TexCoords[i * 2 + 1] = 1;
            for (Int16 i = 0; i != LengthSegments; i++)
            {
                Points[i * 3]=16;
                Points[(i + LengthSegments) * 3] = -16;
            }
        }
        public void DrawScene()
        {
            bool tmp2 = current.EnableCullFace;
            current.EnableDoubleNormals = true;
            //current.EnableBackFace = true;
            BazisMatrix Matrix1 = new BazisMatrix(ref current);
            current.RotateX(Math.PI);
            //current.Scalef(1, -1, 1);
            current.EnableCullFace = false;
            SceneModels[0].Draw(ref current, ref SceneTextures[0]);
            BazisMatrix Matrix2 = new BazisMatrix(ref current);
            current.Translatef(0, 7, -12);
            BazisMatrix Matrix3 = new BazisMatrix(ref current);
            current.Scalef(1, 0.8, 1);
            SceneModels[1].Draw(ref current, ref SceneTextures[1]);
            Matrix3.SetToBuffer(ref current);
            current.Translatef(18, -8, 0);
            current.EnableCullFace = true;
            SceneModels[2].Draw(ref current, ref SceneTextures[2]);
            current.Translatef(-36, 0, 0);
            current.RotateY(Math.PI);
            SceneModels[2].Draw(ref current, ref SceneTextures[2]);
            Matrix2.SetToBuffer(ref current);
            current.Translatef(-35,18, 0);
            current.EnableCullFace = false;
            SceneModels[3].Draw(ref current, ref SceneTextures[3]);
            Matrix2.SetToBuffer(ref current);
            current.Translatef(17, 18, 22);
            current.RotateX(-SceneAngle2);
            current.Translatef(0, 0, -22);
            SceneModels[4].Draw(ref current, ref SceneTextures[3]);
            Matrix2.SetToBuffer(ref current);
            current.Translatef(-1, -1.5,-25);
            current.RotateX(SceneAngle1);
            current.Translatef(0, 0, -5);
            current.EnableCullFace = false;
            SceneModels[5].Draw(ref current, ref SceneTextures[4]);
            if (ScenePrintStarted)
            {                                
                bool tmp = current.EnableLighting;
                current.EnableLighting = false;
                Matrix2.SetToBuffer(ref current);
                for (Int32 i = 0; i != LengthSegments; i++)
                {
                    GetYZ(ParamT + LengthT * i / LengthSegments, out Points[i * 3 + 1], out Points[i * 3 + 2]
                        , out Points[(i + LengthSegments) * 3 + 1], out Points[(i + LengthSegments) * 3 + 2]);
                    if (ParamT + LengthT * i / LengthSegments > 60)
                    { TexCoords[i * 2] = (double)i / (LengthSegments - 1); TexCoords[(i + LengthSegments) * 2] = (double)i / (LengthSegments - 1); }
                }
                current.PaintFaces(ref Points, ref TexCoords, ref Faces_TexFaces, true, ref color,
                                                            ref SceneTextures[5], ref Faces_TexFaces);
                
                current.EnableLighting = tmp;
            }
            Matrix1.SetToBuffer(ref current);
            current.EnableCullFace = tmp2;
        }


        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            current = new Buffers();
            current.ClearColor(100, 255, 100);
            Model = new MorphingModel("Sphere.MX1",true,true);
            Model.SetColor(255, 255, 0);
            tex = new Texture("02.JPG");
            MainTexture= new Texture("01.JPG");
            LoadScene();
            LastFixedFPS = Buffers.GetTickCount();
            LastTickCount = LastFixedFPS;
            FPS = 0;
            Form1_SizeChanged(sender, null);
        }

        private void Form1_SizeChanged(object sender, EventArgs e)
        {
            current.Viewport(this.Handle,0, 0, this.Width, this.Height);
            current.FillClearBuf(ref MainTexture);
            PaintSomething();
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            current.SwapBuffers();
        }

        public void PaintSomething()
        {
            Int32 dT = Buffers.GetTickCount();            
            if (dT == LastTickCount) dT += 1;
            current.Clear();
            current.ZeroBazis();

            if (RotateXModel)RotateAngleX += 2*RotateSpeed * (dT - LastTickCount);
            if (RotateYModel)RotateAngleY +=   RotateSpeed * (dT - LastTickCount);
            current.RotateY(RotateAngleY);
            current.RotateX(RotateAngleX);
            if (RotateLight)
            {
                LightAngle += RotateSpeed * (dT - LastTickCount);
                current.SetLightPos(Math.Sin(-LightAngle), 0, Math.Cos(LightAngle));
            }
            
            current.Scalef(Scale, Scale, Scale);
            if (PaintScene)
            {
                current.Scalef(0.03, 0.03, 0.03);
                DrawScene();
                SceneAngle1 += (dT - LastTickCount) * (ScenePrinterOpen ? OpenSpeed1 : -OpenSpeed1);
                SceneAngle2 += (dT - LastTickCount) * (SceneScannerOpen ? OpenSpeed2 : -OpenSpeed2);
                if (ScenePrintStarted) ParamT += SpeedT * (dT - LastTickCount);
                if (SceneAngle1 > 0) SceneAngle1 = 0;
                if (SceneAngle1 < -Math.PI / 2) SceneAngle1 = -Math.PI / 2;
                if (SceneAngle2 < 0.01) SceneAngle2 = 0.01;
                if (SceneAngle2 > Math.PI * 2 / 3) SceneAngle2 = Math.PI * 2 / 3;
                if (ParamT > 85) ScenePrintStarted = false;
            }
            else { current.EnableCullFace = OnlyFaceNormals; Model.Draw(ref current, ref tex); }
            current.SwapBuffers();
            FPS+=1;
            if (dT - LastFixedFPS > 1000)
                {
                LastFixedFPS = dT;
                this.Text = "FPS = " + FPS.ToString("###") + ";  Triangles count= " + current.TrianglesCount.ToString() ;
                FPS = 0;
                }
                LastTickCount = dT;
        }

        public void Test()
        {
            current.ZeroBazis();
            Int32 count = 50;
            Int32 tick1 = Buffers.GetTickCount();
            for (int i = 0; i < count; i++)
                current.Clear();
            Int32 tick2 = Buffers.GetTickCount();
            tick1 = tick2 - tick1;
            for (int i = 0; i < count; i++)
                Model.Draw(ref current, ref tex);
            Int32 tick3 = Buffers.GetTickCount();
            tick2 = tick3 - tick2;
            for (int i = 0; i < count; i++)
                current.SwapBuffers();
            tick3 = Buffers.GetTickCount() - tick3;
            MessageBox.Show("Очистка:" + ((double)(tick1 / count / 1.0001)).ToString("#.##") + "; Прорисовка на BitMap:" + ((double)(tick2 / count / 1.0001)).ToString("#.##") +
                "; Прорисовка на экран:" + ((double)(tick3 / count / 1.0001)).ToString("#.##") + "; Сумма:" + ((double)((tick1 + tick2 + tick3) / 1.0001 / count)).ToString("#.##") +
                "; Ожидаемый FPS:" + ((double)(count * 1001 / 1.001 / (tick1 + tick2 + tick3))).ToString("#.##"));
        }

        private void Form1_Click(object sender, EventArgs e)
        {
           // this.Test();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            PaintSomething();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                current.EnableBackFace = false;
                current.EnableCullFace = true;
                current.EnableLighting = true;
                button4.Enabled = true;
                button2.Enabled = true;
                PaintScene = false;
                if (openFileDialog1.FilterIndex == 1)
                {
                    Model = new MorphingModel(openFileDialog1.FileName, true, true);
                    Model.SetColor(ModelColor);
                }
                else
                {
                    Model = new MorphingModel(openFileDialog1.FileName); 
                }
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (colorDialog1.ShowDialog()==DialogResult.OK)
            {ModelColor=colorDialog1.Color;Model.SetColor(ModelColor);}
        }

        private void button3_Click(object sender, EventArgs e)
        {
            if (colorDialog2.ShowDialog()==DialogResult.OK)
            { ClearColor = colorDialog2.Color; current.ClearColor(ClearColor); current.FillClearBuf(ref MainTexture); }            
        }

        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            Scale = (double)(trackBar1.Value )/100;
        }

        private void button4_Click(object sender, EventArgs e)
        {
            if (openFileDialog2.ShowDialog() == DialogResult.OK)
                tex = new Texture(openFileDialog2.FileName);
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Q: ScenePrinterOpen = !ScenePrinterOpen; ScenePrintStarted = false; break;
                case Keys.W: SceneScannerOpen = !SceneScannerOpen; break;
                case Keys.E: ScenePrintStarted =!ScenePrintStarted&&ScenePrinterOpen; 
                    if (ScenePrintStarted)
                    {   ParamT = -50; 
                        for (Int16 i = 0; i != LengthSegments*2; i++)
                            TexCoords[i * 2] = 0;    
                    } break;
                case Keys.L: RotateLight = !RotateLight;
                    if (!RotateLight)
                    { LightAngle = 0;  current.SetLightPos(0, 0,1); }
                    else current.EnableLightPos = true;break;
                case Keys.S: current.EnableLighting = !current.EnableLighting;break;
                case Keys.X: RotateXModel = !RotateXModel; break;
                case Keys.Y: RotateYModel = !RotateYModel; break;
                case Keys.D: OnlyFaceNormals = !OnlyFaceNormals; break;
            }
        }

        private void button5_Click(object sender, EventArgs e)
        {
            if (openFileDialog2.ShowDialog() == DialogResult.OK)
            {
                MainTexture = new Texture(openFileDialog2.FileName);
                current.FillClearBuf(ref MainTexture);
            }
        }

    }
}